package org.goldenport.g3.messages.http

import scala.collection.JavaConversions._
import javax.servlet.http.HttpServletRequest
import com.asamioffice.goldenport.servlet.ServletUtil.path_info
import org.goldenport.g3.G3Command
import org.goldenport.g3.messages._
import org.goldenport.g3.servlet.ServletUtil._
import org.apache.commons.fileupload.servlet.ServletFileUpload
import org.apache.commons.fileupload.FileItem
import org.apache.commons.fileupload.disk.DiskFileItemFactory

/**
 * @since   Apr. 12, 2010
 * @version Oct. 24, 2010
 * @version Dec.  5, 2011
 * @author  ASAMI, Tomoharu
 */
trait HttpCommand extends RestCommand {
  val request: Option[HttpServletRequest]
}

object GET {
  def apply(uri: String, params: Record = null, req: HttpServletRequest = null) = {
    new GET(uri, Option(params), Option(req))
  }

  def apply(uri: String, req: HttpServletRequest) = {
    new GET(uri,
            makeRecord(req),
            Some(req))
  }

  def apply(req: HttpServletRequest) = {
    new GET(path_info(req),
            makeRecord(req),
            Some(req))
  }
}

object POST {
  def apply(uri: String, params: Record = null) = {
    new POST(uri, Option(params))
  }

  def apply(uri: String, req: HttpServletRequest) = {
    new POST(uri,
             makeRecord(req),
             Some(req))
  }

  def apply(req: HttpServletRequest) = {
    new POST(path_info(req),
             makeRecord(req),
             Some(req))
  }
}

object PUT {
  def apply(uri: String, params: Record = null) = {
    new PUT(uri, Option(params))
  }

  def apply(req: HttpServletRequest) = {
    new PUT(path_info(req),
            makeRecord(req),
            Some(req))
  }
}

object DELETE {
  def apply(uri: String, params: Record = null) = {
    new DELETE(uri, Option(params))
  }

  def apply(req: HttpServletRequest) = {
    new DELETE(path_info(req),
               makeRecord(req),
               Some(req))
  }
}

/**
 * Http GET
 * WebDAV GET
 * safe, idempotent
 */
class GET(
  uri: String,
  val params: Option[Record] = None,
  val request: Option[HttpServletRequest] = None
) extends Get(uri, params) with HttpCommand

/**
 * Http HEAD
 * WebDAV GET
 * safe, idempotent
 */
case class HEAD(name: String)

/**
 * Http POST
 * WebDAV POST
 */
class POST(
  uri: String,
  val params: Option[Record] = None,
  val request: Option[HttpServletRequest] = None
) extends Post(uri, params) with HttpCommand {
  import scala.collection.JavaConverters._

  lazy val attachments: (List[FileAttachment], List[FieldAttachment]) = {
    request match {
      case None => (Nil, Nil)
      case Some(req) => {
        val factory = new DiskFileItemFactory()
        val sfu = new ServletFileUpload(factory)
        (sfu.parseRequest(req).asScala.toList foldRight
            Pair(List.empty[FileAttachment], List.empty[FieldAttachment])) { 
          case (x, (s1, s2)) => x match {
            case item: FileItem => {
              if (item.isFormField) (s1, new FieldAttachment(item) :: s2)
              else (new FileAttachment(item) :: s1, s2)
            }
          }
        }
      }
    }
  }

  override def getFileAttachments() = attachments._1
  override def getFieldAttachments() = attachments._2
}

/**
 * Http PUT
 * WebDAV PUT
 * idempotent
 */
class PUT(
  uri: String,
  val params: Option[Record] = None,
  val request: Option[HttpServletRequest] = None
) extends Put(uri, params) with HttpCommand

/**
 * Http DELETE
 * WebDAV DELETE
 * idempotent
 */
class DELETE(
  uri: String,
  val params: Option[Record] = None,
  val request: Option[HttpServletRequest] = None
) extends Delete(uri, params) with HttpCommand

/**
 * Http OPTIONS
 */
case class OPTIONS(name: String)

/**
 * Http TRACE
 */
case class TRACE(name: String)

/**
 * Http CONNECT
 */
case class CONNECT(name: String)

/**
 * Http PATCH
 */
case class PATCH(name: String)

/**
 * WebDAV PROPFIND
 */
case class PROPFIND(name: String)

/**
 * WebDAV PROPPATCH
 */
case class PROPPATCH(name: String)

/**
 * WebDAV MKCOL
 */
case class MKCOL(name: String)

/**
 * WebDAV COPY
 */
case class COPY(name: String)

/**
 * WebDAV MOVE
 */
case class MOVE(name: String)

/**
 * WebDAV LOCK
 */
case class LOCK(name: String)

/**
 * WebDAV UNLOCK
 */
case class UNLOCK(name: String)
